#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
//using namespace std;
//条件等待是线程间同步的一种手段
//条件变量是用来等待线程(在等待过程中会释放锁)而不是上锁的，条件变量通常和互斥锁一起使用。
//条件变量之所以要和互斥锁一起使用，主要是因为互斥锁的一个明显的特点就是它只有两种状态：锁定和非锁定
//而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足，所以互斥锁和条件变量通常一起使用
//当条件满足的时候，线程通常解锁并等待该条件发生变化，一旦另一个线程修改了环境变量，就会通知相应的环境变量唤醒一个或者多个被这个条件变量阻塞的线程。
//这些被唤醒的线程将重新上锁，并测试条件是否满足。一般来说条件变量被用于线程间的同步；当条件不满足的时候，允许其中的一个执行流挂起和等待

const int defaultcap = 5;
template<class T>
class RingQueue
{
private:
void P(sem_t& sem)
{
    sem_wait(&sem);
}
void V(sem_t& sem)
{
    sem_post(&sem);
}
void LOCK(pthread_mutex_t& mutex)
{
    pthread_mutex_lock(&mutex);
}
void UNLOCK(pthread_mutex_t& mutex)
{
    pthread_mutex_unlock(&mutex);
}
public:
    RingQueue(int cap=defaultcap)
    :ringqueue_(cap)
    ,p_step_(0)
    ,cap_(cap)
    ,c_step_(0)
    {
        sem_init(&cdata_sem_,0,0);
        sem_init(&pspace_sem_,0,cap_);
        pthread_mutex_init(&c_mutex_,nullptr);
        pthread_mutex_init(&p_mutex_,nullptr);
    }
    void Push(T& in)
    {
        P(pspace_sem_);//p--
        LOCK(p_mutex_);

        ringqueue_[p_step_]=in;
        p_step_++;
        p_step_%=cap_;

        UNLOCK(p_mutex_);
        V(cdata_sem_);
    }
    void Pop(T* out)
    {
        P(cdata_sem_);
        LOCK(c_mutex_);

        *out=ringqueue_[c_step_];
        c_step_++;
        c_step_%=cap_;
        
        UNLOCK(c_mutex_);
        V(pspace_sem_);
    }
    ~RingQueue()
    {
        sem_destroy(&cdata_sem_);
        sem_destroy(&pspace_sem_);
        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }

private:
std::vector<T> ringqueue_;
int cap_;//容量
int p_step_;//生产者下标
int c_step_;//消费者下标

sem_t cdata_sem_;  // 消费者关注的数据资源
sem_t pspace_sem_; // 生产者关注的空间资源

pthread_mutex_t c_mutex_;
pthread_mutex_t p_mutex_;
};